﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DiscoveryLogic.DataViz.NetworkDiagram.Measures
{
    /// <summary>
    /// 
    /// </summary>
    public class BetweennessCentralityMeasure:IVerticeMeasure
    {
        #region Implementation of IVerticeMeasure
        /// <summary>
        /// 
        /// </summary>
        /// <param name="g"></param>
        /// <param name="vs"></param>
        /// <returns></returns>
        public double GetVerticeMeasure(Graph g, params Vertice[] vs)
        {
            if(vs==null || vs.Length !=1)
                throw new Exception("Betweenness centrality requires one vertices specified");

            Vertice v = vs[0];
            Vertice[] vertices=new Vertice[g.Vertices.Count];
            g.Vertices.Values.CopyTo(vertices,0);
            int geodesicPathThroughV = 0;
            int geodesicPath = 0;
            for(int i=0;i<vertices.Length;i++)
            {
                if(vertices[i].ID==v.ID)
                    continue;
                Vertice s = vertices[i];
                for(int k=i+1;k<vertices.Length;k++)
                {
                    if(vertices[k].ID==v.ID)
                        continue;
                    Vertice t = vertices[k];
                    DijkstraDistanceMeasure shortestDist=new DijkstraDistanceMeasure();
                    shortestDist.Init(g, s);
                    List<Guid> path=new List<Guid>();
                    double distanceST = shortestDist.ShortestPathTo(t, ref path);
                    if(distanceST<double.PositiveInfinity)
                    {
                        geodesicPath++;
                        if (path.Contains(v.ID))
                            geodesicPathThroughV++;
                    }
                }
            }
            double centrality = 0;
            if (geodesicPath > 0)
                centrality = ((double) geodesicPathThroughV)/geodesicPath;
            int pathNotThroughV = 0;
            foreach(Edge e in g.Edges.Values)
            {
                if (e.VerticeID1 != v.ID && e.VerticeID2 != v.ID)
                    pathNotThroughV++;
            }
            if (pathNotThroughV > 0)
                centrality = centrality/pathNotThroughV;
            return centrality;
        }

        #endregion

        #region Implementation of IMeasure

        public MeasureType MeasureType
        {
            get
            {
                return Measures.MeasureType.Vertice;
            }
        }

        public string MeasureName
        {
            get
            {
                return "Centrality";
            }
        }

        public string Algorithm
        {
            get
            {
                return "Freeman";
            }
        }

        public string Description
        {
            get
            {
                return "";
            }
        }

        #endregion
    }
}
